﻿using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using System.Diagnostics;
using Volo.Abp.DependencyInjection;
using CTP.CRM.Core.Common.Attributes;

namespace CTP.CRM.Core.Filter
{
    public class RequestLogFilter : IAsyncActionFilter, IFilterMetadata, ISingletonDependency
    {
        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            RequestLogInfo logInfo = default(RequestLogInfo);
            try
            {
                HttpContext httpContext = context.HttpContext;
                HttpRequest httpRequest = httpContext.Request;
                DateTime currentTime = DateTime.Now;
                string requestCode = Activity.Current?.TraceId.ToString() ?? "N/A";
                string[] paramsterNames = (context?.ActionDescriptor?.Parameters)?.Where((ParameterDescriptor x) => x.BindingInfo != null && x.BindingInfo.BindingSource != BindingSource.Services)?.Select((ParameterDescriptor x) => x.Name)?.ToArray();
                logInfo.RequestParamsters = ((httpRequest.Method == "GET") ? httpRequest.QueryString.ToString() : JsonConvert.SerializeObject(context?.ActionArguments?.Where((KeyValuePair<string, object> m) => paramsterNames.Contains(m.Key))));
                context.HttpContext.Request.Headers.Add("CTP_Request_Code", requestCode);
                context.HttpContext.Request.Headers.Add("CTP_Request_Parameter", logInfo.RequestParamsters);
                Stopwatch sw = new Stopwatch();
                sw.Start();
                ActionExecutedContext actionContext = await next();
                sw.Stop();
                httpContext.Response.Headers.Add("TraceId", requestCode);
                logInfo.RequestCode = requestCode;
                logInfo.TotalTime = sw.ElapsedMilliseconds;
                logInfo.RequestPath = httpRequest.Path;
                logInfo.ExecuteTime = currentTime;
                if (actionContext.Exception != null)
                {
                    logInfo.Result = actionContext.Exception.ToString();
                }
                else if (!context.ActionDescriptor.EndpointMetadata.Any((object m) => m.GetType() == typeof(IgnoreLogDetailAttribute)))
                {
                    string exceptionMsg = ((actionContext.Exception != null) ? actionContext.Exception.ToString() : ((!(actionContext.Result is FileResult)) ? ((string)JsonConvert.SerializeObject(((dynamic)actionContext.Result)?.Value)) : "...[文件流结果日志已忽略打印]..."));
                    logInfo.Result = exceptionMsg;
                }
                else
                {
                    logInfo.Result = "...[日志已忽略打印]...";
                }

                logInfo.Headers = httpRequest.Headers;
                logInfo.Exception = actionContext.Exception;
            }
            catch (Exception ex2)
            {
                Exception ex = ex2;
                Console.WriteLine($"记录日志发生未处理异常：{ex}");
            }
            finally
            {
                string log = string.Format("\r\n    |-请求编号：{0}\r\n    |-消耗时间：{1}毫秒\r\n    |-请求路径：{2}\r\n    |-执行时间：{3}\r\n    |-用户信息：{4}\r\n    |-请求参数：{5}\r\n    |-执行结果：{6}\r\n    |-Headers：{7}", logInfo.RequestCode, logInfo.TotalTime, logInfo.RequestPath, logInfo.ExecuteTime.ToString("yyyy-MM-dd HH:mm:ss ffff"), logInfo.UserInfo, logInfo.RequestParamsters, logInfo.Result, (logInfo.Headers == null) ? "" : JsonConvert.SerializeObject(logInfo.Headers));
                LogHelper.Info(log, false);
            }
        }
    }
}
